package btb.net;

import java.io.IOException;
import java.util.ArrayList;

import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;

import btb.engine.ATask;
import btb.engine.CEvent;
import btb.engine.CTaskMessenger;
import btb.net.CChannel.NChannelProfile;
import btb.net.CNetwork.NChannelMap;
import btb.net.CNetwork.NChatMessage;
import btb.net.CNetwork.NSubscribe;
import btb.net.CNetwork.NChatOpResults;
import btb.net.CNetwork.NUnsubscribe;
import btb.net.CNetwork.NUpdateChannelList;
import btb.util.AObjectList;
import btb.util.CLogger;

public class CChatServer extends ATask
{
	protected Server server = null;
	
	protected NChannelMap channelList = null;

	/*
	protected static class NChatConnection extends Connection {
		public int[] subscribedChannels;
	}*/
	
	protected Listener chatListener = new Listener()
	{	
		public void received(Connection _c, Object _o)
		{				
			if(_o instanceof NChatMessage)
			{
				NChatMessage ncm = (NChatMessage) _o;
				relayMessage(_c, ncm);
			}
			else if(_o instanceof NSubscribe)
			{
				NSubscribe ns = (NSubscribe) _o;
				subscribeToChannel(_c, ns.user, ns.channelName);
			}
			else if(_o instanceof NUnsubscribe)
			{
				NUnsubscribe nus = (NUnsubscribe) _o;
				unsubscribeFromChannel(_c, nus.userName, nus.channelName);
			}
			if(_o instanceof NUpdateChannelList)
			{
				returnChannelList(_c);
			}
		}
	};
	
	public CChatServer(ATask _parentTask, int _taskId, CTaskMessenger _mailbox) throws IOException
	{
		super(_parentTask, _taskId, _mailbox);
		
		this.channelList = new NChannelMap();
		
		try
		{
			this.server = new Server();
			
			CNetwork.register(this.server);
			
			this.server.addListener(this.chatListener);
			
			this.server.bind(CNetwork.CHAT_SERVER_PORT);
			this.server.start();
		}
		catch(IOException ioe)
		{
			throw new IOException("Unable to construct CChatServer", ioe);
		}
		
		CLogger.cond_debug("chat server", "Initialized.");
		createDefaultChannels();
	}
	
	protected void relayMessage(Connection _c, NChatMessage _msg)
	{
		int pos;
		if((pos = channelList.findChannelByName(_msg.channelName)) > -1)
		{
			CChannel channel = (CChannel) channelList.getList()[pos];
			for(int i = 0; i < channel.getSubscribers().getCount(); i++)
			{
				CUser recipient = (CUser) channel.getSubscribers().getList()[i];
				Connection conn = recipient.getConnection();
				conn.sendTCP(_msg);
			}
		}
		else
		{
			returnChatOpResults(_c, _msg.channelName, NChatOpResults.SEND_MSG_ATTEMPT, false);
		}
	}
	
	protected void createDefaultChannels()
	{
		createChannel("General Chat");
		createChannel("Mage Chat");
		createChannel("Rogue Chat");
		createChannel("Warrior Chat");
	}
	
	protected void createChannel(String _channelName)
	{
		CChannel newChannel = new CChannel(_channelName);
		channelList.add(newChannel);
	}
	
	protected void destroyChannel(String _channelName)
	{
		int pos = channelList.findChannelByName(_channelName);
		channelList.removeByIndex(pos);
	}
	
	public void subscribeToChannel(Connection _c, CUser newUser, String _channelName)
	{
		int pos;
		if((pos = channelList.findChannelByName(_channelName)) > -1)
		{
			CChannel channel = (CChannel) channelList.getList()[pos];
			channel.addSubscriber(newUser);
			returnChatOpResults(_c, _channelName, NChatOpResults.SUBSCRIBE_ATTEMPT, true);
		}
		else
		{
			returnChatOpResults(_c, _channelName, NChatOpResults.SUBSCRIBE_ATTEMPT, false);
		}
	}
	
	public void unsubscribeFromChannel(Connection _c, String _userName, String _channelName)
	{
		int pos;
		if((pos = channelList.findChannelByName(_channelName)) > -1)
		{
			CChannel channel = (CChannel) channelList.getList()[pos];
			channel.removeSubscriberByName(_userName);
			returnChatOpResults(_c, _channelName, NChatOpResults.UNSUBSCRIBE_ATTEMPT, true);
		}
		else
		{
			returnChatOpResults(_c, _channelName, NChatOpResults.UNSUBSCRIBE_ATTEMPT, false);
		}
	}
	
	public void returnChatOpResults(Connection _c, String _channelName, int _operation, boolean _success)
	{
		NChatOpResults nsres = new NChatOpResults();
		nsres.channelName = _channelName;
		nsres.operation = _operation;
		nsres.success = _success;
		_c.sendTCP(nsres);
	}
	
	public void returnChannelList(Connection _c)
	{
		NUpdateChannelList clist = new NUpdateChannelList();
		clist.channels = new ArrayList<NChannelProfile>(channelList.getCount());
		for(int i = 0; i < channelList.getCount(); i++)
		{
			clist.channels.add((NChannelProfile)((CChannel) channelList.getList()[i]).getProfile());
		}
		
		_c.sendTCP(clist);
	}
	
	public void update()
	{
		
	}
	
	public void handleDeath()
	{
		
	}
	
	public void handleEvent(CEvent _e) {
		
	}
}
